/** Copyright (c) 2012, peter.ducai@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the Peter Ducai nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL PETER "daemonna" DUCAI BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package com.daemonna.fluentlee_core.managers;

import com.daemonna.fluentlee_core.cli.executor;
import com.daemonna.fluentlee_core.cli.remote_shell;
import com.daemonna.fluentlee_core.crypto.Whirlpool;
import com.daemonna.fluentlee_core.job.job;
import com.daemonna.fluentlee_core.job.schedule;
import com.daemonna.fluentlee_core.objects.connector;
import com.daemonna.fluentlee_core.pools.connector_pool;
import com.daemonna.fluentlee_core.pools.schedule_pool;
import com.daemonna.fluentlee_core.utils.custom_string_parser;
import com.jcraft.jsch.JSchException;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
 * @author peter 'daemonna' ducai @author peter.ducai@gmail.com @author
 * http://code.google.com/p/fluentlee/
 */
public class execution_manager { //to execute all jobs from schedule_pool

    public execution_manager() {
        System.out.println("Execution Manager starting...");
    }

    public void execute_schedule(int sched_index) throws SQLException, Exception {

        schedule_pool.getInstance().locked = true; //lock down pool


        

        System.out.println("EXECUTING " + sched_index);

        if (schedule_pool.getInstance().scheds[sched_index] != null) {

            long schedstartTime = System.currentTimeMillis();
            schedule_pool.getInstance().scheds[sched_index].start_time = schedstartTime;
            schedule_pool.getInstance().scheds[sched_index].state = schedule.status.ACTIVE;

            /*
             * list all suites
             */
            for (int x = 0; x < schedule_pool.getInstance().scheds[sched_index].suites.length; x++) {


                /*
                 * list all jobs inside of suite
                 */
                if (schedule_pool.getInstance().scheds[sched_index].suites[x] != null) {

                    System.out.println("suites " + x);


                    for (int v = 0; v < schedule_pool.getInstance().scheds[sched_index].suites[x].jobs.length; v++) {

                        if (schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v] != null) {
                            if (schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].status == job.jobstatus.INACTIVE) {
                                

                                schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].start_time = System.currentTimeMillis();
                                schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].status = job.jobstatus.RUNNING;

                                /*
                                 * determine job type and execute it
                                 */
                                if (schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].type == job.jobtype.RUN) {

                                    /*
                                     * run local command
                                     */
                                    execute_run(sched_index, x, v);

                                } else if (schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].type == job.jobtype.SQL) {

                                    /*
                                     * execute sql
                                     */
                                    int zz = connector_pool.getInstance().get_index(schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].con_name1);
                                    String cmd = schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].command_value;

                                    execute_sql(cmd, connector_pool.getInstance().conns[zz], sched_index, x, v);

                                    /*
                                     * mark job as completed
                                     */
                                    schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].status = job.jobstatus.COMPLETED;

                                } else if (schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].type == job.jobtype.SQL_COMPARE) {

                                    /*
                                     * compare 2 sql resultsets
                                     */

                                    execute_sql_compare(null, null, sched_index, x, v);

                                    /*
                                     * mark job as completed
                                     */
                                    schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].status = job.jobstatus.COMPLETED;

                                } else if (schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].type == job.jobtype.CHECKSUM) {

                                    /*
                                     * create Whirlpool checksum of string or
                                     * file
                                     */

                                    execute_checksum();

                                    /*
                                     * mark job as completed
                                     */
                                    schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].status = job.jobstatus.COMPLETED;

                                } else if (schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].type == job.jobtype.CRYPTO) {

                                    /*
                                     * encrypt/decrypt with Rijndael
                                     */



                                    /*
                                     * mark job as completed
                                     */
                                    schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].status = job.jobstatus.COMPLETED;

                                } else if (schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].type == job.jobtype.SSH) {
                                    /*
                                     * call remote shell
                                     */
                                    String usr = schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].ssh_username;
                                    String host = schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].ssh_host;
                                    int pt = schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].ssh_port;
                                    String com = schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].command_value;
                                    String pass = schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].ssh_pass;

                                    execute_ssh(usr, host, pt, com, pass, sched_index, x, v);

                                    /*
                                     * mark job as completed
                                     */
                                    schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].status = job.jobstatus.COMPLETED;
                                } else if (schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].type == job.jobtype.MAVEN_RUN) {

                                    /*
                                     * call: mvn exec:java
                                     * -Dexec.mainClass="com.mycompany.App"
                                     */

                                    execute_maven(sched_index, x, v);

                                    /*
                                     * mark job as completed
                                     */
                                    schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].status = job.jobstatus.COMPLETED;
                                }
                                
                                schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].end_time = System.currentTimeMillis();
                            }
                        }

                        
                    }


                }
            }


            long endTime = System.currentTimeMillis();
            schedule_pool.getInstance().scheds[sched_index].end_time = endTime;
            /*
             * mark schedule as COMPLETED, so it can be reported
             */
            schedule_pool.getInstance().scheds[sched_index].state = schedule.status.COMPLETED;
        }
        schedule_pool.getInstance().locked = false; //lock down pool      

    }

    private void execute_run(int sched_index, int x, int v) {

        System.out.println("EXECUTING------------------------------------------------------------------------");
        /*
         * mark job as running
         */


        executor ex = new executor();

        /*
         * get command and create array of params from it
         */
        String preparams = schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].command_value;

        custom_string_parser pars = new custom_string_parser();
        String[] cmd = pars.stringToArray(preparams);

        schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].start_time = System.currentTimeMillis();

        try {
            int exitval = ex.executor(cmd);
            if (exitval == 0) {
                schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].result = job.jobresult.PASS;
            } else {
                schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].result = job.jobresult.FAIL;
            }
        } catch (IOException ex1) {
            Logger.getLogger(execution_manager.class.getName()).log(Level.SEVERE, null, ex1);
        }

        schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].end_time = System.currentTimeMillis();
    }

    private void execute_sql(String sql, connector con, int sched_index, int x, int v) throws SQLException, Exception {

        con.init_connector();
        con.execute_sql(sql, sched_index, x, v);

    }

    private void execute_sql_compare(ResultSet rs1, ResultSet rs2, int sched_index, int x, int v) {
        //TODO        
    }

    private void execute_checksum() {

        Whirlpool w = new Whirlpool();
        byte[] digest = new byte[Whirlpool.DIGESTBITS];
        byte[] data = "asdklfaskldfkl4fklj-09s080gvbaus tw4vn85ta4t88gartvc4tmc8pgf".getBytes();

        Arrays.fill(data, (byte) 0);

        System.out.println("1. In this example the data-string is the empty string, i.e. the string of length zero.\n");
        w.NESSIEinit();
        w.NESSIEfinalize(digest);
        System.out.println("The hash-code is the following 512-bit string.\n\n" + digest.toString() + "\n");

    }

    private void execute_ssh(String username, String host, int port, String command, String pass, int sched_index, int x, int v) {
        try {
            remote_shell rsh = new remote_shell();
            rsh.execute_ssh(username, host, pass, command, port);
        } catch (IOException ex) {
            Logger.getLogger(execution_manager.class.getName()).log(Level.SEVERE, null, ex);
        } catch (JSchException ex) {
            Logger.getLogger(execution_manager.class.getName()).log(Level.SEVERE, null, ex);
        }

        schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].result = job.jobresult.PASS;
    }

    private void execute_maven(int sched_index, int x, int v) {

        executor ex = new executor();

        /*
         * get command and create array of params from it
         */
        String preparams = "mvn exec:java -Dexec.mainClass=" + schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].command_value + "\"";

        custom_string_parser pars = new custom_string_parser();
        String[] cmd = pars.stringToArray(preparams);
        try {
            ex.executor(cmd);
        } catch (IOException ex1) {
            Logger.getLogger(execution_manager.class.getName()).log(Level.SEVERE, null, ex1);
        }

        schedule_pool.getInstance().scheds[sched_index].suites[x].jobs[v].result = job.jobresult.PASS;
    }
}
